package com.easylinkin.linkappapi.lobar.service.impl;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.common.utils.excel.ExcelReadUtil;
import com.easylinkin.linkappapi.lobar.dto.GroupDTO;
import com.easylinkin.linkappapi.lobar.dto.LaborCompanyGroupDto;
import com.easylinkin.linkappapi.lobar.dto.LaborCompanyProjectDTO;
import com.easylinkin.linkappapi.lobar.dto.UserProjectDTO;
import com.easylinkin.linkappapi.lobar.dto.excel.ExcelResultDTO;
import com.easylinkin.linkappapi.lobar.dto.excel.ExcelResultDetailDTO;
import com.easylinkin.linkappapi.lobar.entity.Gate;
import com.easylinkin.linkappapi.lobar.entity.Group;
import com.easylinkin.linkappapi.lobar.entity.LaborCompany;
import com.easylinkin.linkappapi.lobar.entity.LaborCompanyProject;
import com.easylinkin.linkappapi.lobar.entity.UserProject;
import com.easylinkin.linkappapi.lobar.mapper.GroupMapper;
import com.easylinkin.linkappapi.lobar.mapper.LaborCompanyMapper;
import com.easylinkin.linkappapi.lobar.mapper.LaborCompanyProjectMapper;
import com.easylinkin.linkappapi.lobar.mapper.UserProjectMapper;
import com.easylinkin.linkappapi.lobar.service.GroupService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.lobar.util.LobarUtils;
import com.easylinkin.linkappapi.lobar.vo.LaborCompanyGroupVo;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.easylinkin.linkappapi.security.entity.LinkappUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

/**
 * <p>
 * 闸机表 服务实现类
 * </p>
 *
 * @author kanyuanfeng
 * @since 2022-04-13
 */
@Service
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements GroupService {

  @Resource
  private LinkappUserContextProducer linkappUserContextProducer;

  @Autowired
  private UserProjectMapper userProjectMapper;
  @Autowired
  private LaborCompanyProjectMapper laborCompanyProjectMapper;

  @Resource
  private LaborCompanyMapper companyMapper;

  /**
   * 增加
   * @param group
   */
  @Override
  public void insert(Group group) {
    /**
     * 验证重复
     */
    this.checkExist(group);
    //设置基本属性
    this.setBase(group);
    group.setJoinTime(new Date());
    if (null == group.getStatus()){
      group.setStatus(1);
    }
    this.save(group);
  }

  /**
   * 根据id编辑
   * @param group
   */
  @Override
  public void updateOne(Group group) {
    /**
     * 验证重复
     */
    this.checkExist(group);
    //设置基本属性
    this.setBase(group);
    UpdateWrapper<Group> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("tenant_id_",group.getTenantId())
        .set("name_",group.getName())
        .set("company_project_id_",group.getCompanyProjectId())
        .set("main_people_",group.getMainPeople())
        .set("telephone_",group.getTelephone())
        .set("status_",group.getStatus())
        .set("card_type_",group.getCardType())
        .set("card_no_",group.getCardNo())
        .set("delete_state_",group.getDeleteState())
        .set("join_time_",group.getJoinTime())
        .set("leave_time_",group.getLeaveTime())
        .set("lead_user_id_",group.getLeadUserId())
        .set("service_area_",group.getServiceArea())
        .set("creator_id_",group.getCreatorId())
        .set("create_time_",group.getCreateTime())
        .set("modify_id_",group.getModifyId())
        .set("modify_time_",group.getModifyTime())
        .set("remark_",group.getRemark())
        .eq("id",group.getId());
    baseMapper.update(null,updateWrapper);
  }

  /**
   * @Description: 删除班组（包含批量删除）
   * @author kan yuanfeng
   * @date 2020/11/04 11:42
   */
  @Override
  public void delBatch(Set<String> ids) {
    ids.forEach(id ->{
      QueryWrapper<UserProject> queryWrapper =  new QueryWrapper<>();
      queryWrapper.eq("group_id_",id).eq("delete_state_",1);
      Integer integer = userProjectMapper.selectCount(queryWrapper);
      if (integer > 0){
        throw new BusinessException("该班组下有人员绑定，请先删除人员信息");
      }
      UpdateWrapper<Group> updateWrapper = new UpdateWrapper<>();
      updateWrapper.set("delete_state_",0).set("status_",0)
          .eq("id",id);
      baseMapper.update(null,updateWrapper);
    });
  }

  /**
   * @Description: 进退场
   * @author kan yuanfeng
   * @date 2020/11/04 11:42
   */
  @Override
  public void updateStatus(Group group) {
    //查询其所属单位是否退场
    Group old = baseMapper.selectById(group.getId());
    LaborCompanyProject project = laborCompanyProjectMapper
        .selectById(old.getCompanyProjectId());
    if (Integer.valueOf(0).equals(project.getStatus())){
      throw new BusinessException("班组所属单位已退场");
    }
    if (Integer.valueOf(0).equals(group.getStatus())){
      group.setLeaveTime(new Date());
    }else {
      group.setJoinTime(new Date());
    }
    this.setBase(group);
    this.updateById(group);
    if (Integer.valueOf(0).equals(group.getStatus())){
      //离场要联动下面的人员
      UpdateWrapper<UserProject> updateWrapper = new UpdateWrapper<>();
      updateWrapper.eq("group_id_",group.getId())
          .eq("status_",1)
          .set("modify_time_",group.getModifyTime())
          .set("modify_id_",group.getModifyId())
          .set("status_",group.getStatus())
          .set("leave_time_",group.getLeaveTime());
      userProjectMapper.update(null,updateWrapper);
    }
  }

    @Override
    public RestMessage subOrgGroupTree(LaborCompanyGroupVo laborCompanyGroupVo) {
      LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
      if (laborCompanyGroupVo.getLaborCompany() == null) {
        laborCompanyGroupVo.setLaborCompany(new LaborCompany());
      }
      if (laborCompanyGroupVo.getLaborGroup() == null){
        laborCompanyGroupVo.setLaborGroup(new Group());
      }
      laborCompanyGroupVo.getLaborCompany().setTenantId(linkappUser.getTenantId());
      laborCompanyGroupVo.getLaborGroup().setTenantId(linkappUser.getTenantId());

      //查询数据(因为承建单位、班组都没有层级关系，直接查询就行。每每这个时候就怀恋oracle的树形查询。。。)
      List<LaborCompanyGroupDto> list = companyMapper.selectCompanyGroupDtoList(laborCompanyGroupVo);


      return RestBuilders.successBuilder().data(list).build();
    }

  /**
   * 批量导入花名册
   */
  @Override
  public ExcelResultDTO importExcel(MultipartFile file,String tenantId, Integer type)
      throws Exception{
    List<List<String>> excelList = ExcelReadUtil.getExcelInfo(file, 2, -1, -1);
    if (excelList.size() > 0 && excelList.get(0).size() < 3){
      throw new BusinessException("模板错误,请选择正确的文件导入");
    }
    //创建线程池
    ExecutorService executorService = Executors.newFixedThreadPool(20);
    //创建一个Set保存excel本身的身份证号码
    CompletableFuture<ExcelResultDTO> completableFuture = CompletableFuture
        .supplyAsync(() -> getExcelResultDTO(tenantId,type, excelList),executorService);
    ExcelResultDTO excelResultDTO = completableFuture.get();
    return excelResultDTO;
  }

  /**
   * 执行导入和验证
   * @param type
   * @param excelList
   * @return
   */
  private ExcelResultDTO getExcelResultDTO(String tenantId,Integer type, List<List<String>> excelList) {
    ExcelResultDTO excelResultDTO = new ExcelResultDTO();
    //异常数据组织返回
    List<ExcelResultDetailDTO> excelResultDetailDTOS = new ArrayList<>();
    //成功数据
    //重复数据
    //失败数据
    List<Group> groupList = new ArrayList<>();

    //参建单位
    List<LaborCompanyProjectDTO> companies = this.getCompanies(tenantId);
    //所有的班组
    QueryWrapper<Group> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("tenant_id_",tenantId);
    List<Group> oldGroups = baseMapper.selectList(queryWrapper);
    Set<String> nameSet = new HashSet<>();
    for (int i = 0; i < excelList.size(); i++) {
      ExcelResultDetailDTO excelResultDetailDTO = new ExcelResultDetailDTO();
      //异常提示信息
      List<String> msgs = new ArrayList<>();
      List<String> list = excelList.get(i);
      //验证塞数据
      Group group = new Group();
      //参建单位
      checkAndSetCompany(list.get(0).trim(),msgs,companies,group);
      group.setName(list.get(1).trim());
      if (StringUtils.isBlank(list.get(1))){
        msgs.add("名称为空");
      }
      //通行权限
      group.setServiceArea(getServiceArea(list.get(2).trim(),msgs));
      //校验表格内数据重复
      if (StringUtils.isNotBlank(group.getCompanyProjectId()) && StringUtils.isNotBlank(list.get(1))){
        if (nameSet.contains(group.getCompanyProjectId()+":"+list.get(1).trim())){
          msgs.add("与表格中班组数据重复");
        }else {
          nameSet.add(group.getCompanyProjectId()+":"+list.get(1).trim());
        }
      }
      excelResultDetailDTO.setNo(i+3);
      excelResultDetailDTO.setName(group.getName());
      //失败数据
      if (msgs.size() > 0){
        excelResultDetailDTO.setDetail(StringUtils.join(msgs,","));
        excelResultDetailDTO.setType(1);
        excelResultDetailDTO.setTypeName("失败");
      }else {
        //重复数据
        //查询班组是否重复
        long count = oldGroups.stream()
            .filter(o -> o.getName().equals(group.getName()) &&
                Integer.valueOf(1).equals(o.getDeleteState()) &&
                group.getCompanyProjectId().equals(o.getCompanyProjectId())).count();
        if (count > 0){
          if (!Integer.valueOf(1).equals(type)){
            excelResultDetailDTO.setDetail("班组重复");
            excelResultDetailDTO.setType(2);
            excelResultDetailDTO.setTypeName("重复");
            excelResultDetailDTOS.add(excelResultDetailDTO);
            continue;
          }else {
            ExcelResultDetailDTO repeat = new ExcelResultDetailDTO();
            repeat.setName(excelResultDetailDTO.getName());
            repeat.setNo(excelResultDetailDTO.getNo());
            repeat.setDetail("班组信息覆盖");
            repeat.setType(2);
            repeat.setTypeName("覆盖");
            excelResultDetailDTOS.add(repeat);
          }
        }
        group.setTenantId(tenantId);
        groupList.add(group);
      }
      excelResultDetailDTOS.add(excelResultDetailDTO);
    }
    //汇总
    excelResultDTO.setSum(excelList.size());
    excelResultDTO.setSuccess(groupList.size());
    List<ExcelResultDetailDTO> repeat = excelResultDetailDTOS.stream()
        .filter(e -> Integer.valueOf(2).equals(e.getType())).collect(Collectors.toList());
    excelResultDTO.setRepeat(repeat.size());
    List<ExcelResultDetailDTO> fail = excelResultDetailDTOS.stream()
        .filter(e -> Integer.valueOf(1).equals(e.getType())).collect(Collectors.toList());
    excelResultDTO.setFail(fail.size());
    //去掉类型为空的
    excelResultDetailDTOS.removeIf(e-> null == e.getType());
    excelResultDTO.setExcelResultDetailDTOS(excelResultDetailDTOS);

    //保存数据
    insertList(groupList,type,oldGroups);
    return excelResultDTO;
  }

  /**
   * 设置通行权限
   * @param value
   * @param msgs
   * @return
   */
  private String getServiceArea(String value, List<String> msgs) {
    List<String> serviceArea = new ArrayList<>();
    if (StringUtils.isBlank(value)){
      msgs.add("通行权限为空");
    }else {
      String[] split = value.split(",");
      Map<String, String> serviceAreaMap = GroupDTO.getServiceAreaMap();
      for (int i = 0; i < split.length; i++) {
        String s = split[i].trim();
        String s1 = serviceAreaMap.get(s);
        if (StringUtils.isBlank(s1)){
          msgs.add("通行权限填写错误");
          break;
        }else {
          serviceArea.add(s1);
        }
      }
    }
    return StringUtils.join(serviceArea,",");
  }

  /**
   * 保存数据
   * @param groupList
   * @param type
   * @param oldGroups
   */
  private void insertList(List<Group> groupList, Integer type, List<Group> oldGroups) {
    groupList.forEach(g->{
      //是否重复
      List<Group> groups = oldGroups.stream().filter(
          o -> o.getName().equals(g.getName()) && o.getCompanyProjectId().equals(g.getCompanyProjectId()))
          .collect(Collectors.toList());
      if (groups.size() > 0){
        Group group = groups.get(0);
        this.setBase(g);
        g.setId(group.getId());
        UpdateWrapper<Group> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",group.getId())
            .set("tenant_id_",g.getTenantId())
            .set("company_project_id_",g.getCompanyProjectId())
            .set("name_",g.getName())
            .set("delete_state_",1)
            .set("lead_user_id_",null)
            .set("status_",g.getStatus())
            .set("join_time_",new Date())
            .set("leave_time_",g.getLeaveTime())
            .set("creator_id_",g.getCreatorId())
            .set("create_time_",g.getCreateTime())
            .set("modify_id_",g.getModifyId())
            .set("modify_time_",g.getModifyTime())
            .set("service_area_",g.getServiceArea());
        baseMapper.update(null,updateWrapper);
      }else {
        this.insert(g);
      }
    });
  }

  /**
   * 设置和检查参建单位
   * @param company
   * @param msgs
   * @param group
   */
  private void checkAndSetCompany(String company, List<String> msgs,List<LaborCompanyProjectDTO> companies, Group group) {
    if (StringUtils.isBlank(company)){
      msgs.add("参建单位为空");
    }else {
      List<LaborCompanyProjectDTO> companyProjectDTOS = companies.stream()
          .filter(c -> company.equals(c.getName()))
          .collect(Collectors.toList());
      if (companyProjectDTOS.size() < 1){
        msgs.add("参建单位不存在");
      }else {
        LaborCompanyProjectDTO projectDTO = companyProjectDTOS.get(0);
        group.setCompanyProjectId(projectDTO.getCompanyProjectId());
        group.setStatus(projectDTO.getStatus());
        if (!Integer.valueOf(1).equals(group.getStatus())){
          group.setLeaveTime(new Date());
        }
      }
    }
  }

  @Override
  public IPage<GroupDTO> queryListByPage(RequestModel<GroupDTO> requestModel) {
    Page page = requestModel.getPage();
    GroupDTO groupDTO = requestModel.getCustomQueryParams();
    //项目id 过滤
    groupDTO.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
    IPage<GroupDTO> groupIPage = baseMapper.queryListByPage(page, groupDTO);
    //求在场人数
    groupIPage.getRecords().forEach(r ->{
      QueryWrapper<UserProject> queryWrapper = new QueryWrapper<>();
      queryWrapper.eq("status_",1)
          .eq("group_id_",r.getId());
      Integer integer = userProjectMapper.selectCount(queryWrapper);
      r.setUserNum(null == integer?0:integer);
    });
    return groupIPage;
  }

  /**
   * 获取本项目的参建单位
   */
  private List<LaborCompanyProjectDTO> getCompanies(String tenantId){
    Page page = new Page();
    page.setCurrent(1);
    page.setSize(-1);
    LaborCompanyProjectDTO laborCompany = new LaborCompanyProjectDTO();
    //项目id 过滤
    laborCompany.setTenantId(tenantId);
    IPage<LaborCompanyProjectDTO> laborCompanyProjectIPage = laborCompanyProjectMapper.queryListByPage(page, laborCompany);
    List<LaborCompanyProjectDTO> companyProjectDTOS = laborCompanyProjectIPage.getRecords();
    return companyProjectDTOS;
  }

  /**
   * 验证重复
   */
  private void checkExist(Group group) {
    QueryWrapper<Group> queryWrapper = new QueryWrapper<>();
    //设置判断重复条件
    queryWrapper.eq("name_",group.getName())
                .eq("delete_state_",1)
                .eq("company_project_id_",group.getCompanyProjectId());
    //编辑的时候存在id
    Optional.ofNullable(group.getId()).ifPresent(id -> queryWrapper.ne("id",group.getId()));
    Integer integer = baseMapper.selectCount(queryWrapper);
    if (integer>0){
      throw new BusinessException("对应的劳务公司已存在该班组");
    }
  }

  /**
   * 设置基本属性
   * @param group
   */
  private void setBase(Group group) {
    group.setModifyTime(new Date());
    group.setModifyId(linkappUserContextProducer.getCurrent().getId());
    //没有id就是新增,有就是编辑
    if (StringUtils.isBlank(group.getId())){
      group.setCreatorId(linkappUserContextProducer.getCurrent().getId());
      group.setCreateTime(new Date());
      if (StringUtils.isBlank(group.getTenantId())){
        group.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
      }
    }
  }
}
